#include "av.h"

extern
void lua_object_attach(lua_State * L, lua_av_object * parent, int index) {
	lua_av_object * child = (lua_av_object *) lua_touserdata(L, index);
	lua_av_object_link * link;
	if (child->parent) {
		if (child->parent == parent) {
			return;
		}
		lua_object_detach(L, child);
	}
	link = (lua_av_object_link *) malloc(sizeof(lua_av_object_link));
	link->child = child;
	link->next = parent->children;
	parent->children = link;
	child->parent = parent;
	lua_pushvalue(L, index);
	child->lua_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}
extern void lua_object_detach(lua_State * L, lua_av_object * child) {
	lua_av_object_link * link, *prev;
	lua_av_object * parent = child->parent;
	if (!parent) return;
	prev = 0;
	link = parent->children;
	while (link) {
		if (link->child == child) {
			if (prev) {
				prev->next = link->next;
			} else {
				parent->children = link->next;
			}
			free(link);
			child->parent = 0;
			luaL_unref(L, LUA_REGISTRYINDEX, child->lua_ref);
			child->lua_ref = LUA_NOREF;
		}
		prev = link;
		link = link->next;
	}
	luaL_error(L, "invalid object state, children not linked to its parent");
}

extern
int lua_create_type(lua_State *L, char const * name,
		lua_CFunction gc, lua_CFunction index, lua_CFunction new_index) {
	luaL_newmetatable (L, name);

	lua_pushstring (L, "__gc");
	lua_pushcfunction (L, gc);
	lua_settable (L, -3);

	lua_pushstring (L, "__index");
	lua_pushcfunction (L, index);
	lua_settable (L, -3);

	lua_pushstring (L, "__newindex");
	lua_pushcfunction (L, new_index);
	lua_settable (L, -3);
	return 1;
}

static
int lua_calc_frame_size(lua_State * L) {
	enum PixelFormat pix_fmt = lua_check_pixel_format(L, 1);
	int width = luaL_checkinteger(L, 2);
	int height = luaL_checkinteger(L, 3);

	lua_pushinteger(L, avpicture_get_size(pix_fmt, width, height));
	return 1;
}

static const struct luaL_reg av_lib[] = {
	{"open_format_context", lua_format_context_open},
	{"new_format_context", lua_format_context_new},
	{"guess_format", lua_output_format_guess},
	{"new_packet", lua_new_packet},
	{"new_frame", lua_new_frame},
	{"new_codec_context", lua_new_codec_context},
	{"find_decoder", lua_find_decoder},
	{"find_encoder", lua_find_encoder},
	{"calc_frame_size", lua_calc_frame_size},
	{"new_sws_context", lua_sws_context_new},
	{NULL, NULL},
};

int luaopen_av (lua_State *L) {
	av_register_all();

	lua_register_av_flag_type(L);
	lua_register_format_context(L);
	lua_register_output_format(L);
	lua_register_stream(L);
	lua_register_codec_context(L);
	lua_register_codec(L);
	lua_register_packet(L);
	lua_register_frame(L);
	lua_register_sws_context(L);

	luaL_register (L, "av", av_lib);
	lua_register_av_constants(L);

	lua_pushliteral (L, "_COPYRIGHT");
	lua_pushliteral (L, "Copyright (C) 2001 Fabrice Bellard & the FFMPEG developpers");
	lua_settable (L, -3);
	lua_pushliteral (L, "_DESCRIPTION");
	lua_pushliteral (L, "FFMPEG bindings");
	lua_settable (L, -3);
	lua_pushliteral (L, "_VERSION");
	lua_pushliteral (L, "Lua A/V 0.1");
	lua_settable (L, -3);

	return 1;
}
